package roborescue.examples;

import jason.RoborescueEnv;
import jason.asSyntax.Structure;

import java.rmi.RemoteException;

import robocode.rescue.RobotInfo;
import robocode.rescue.features.Movimentacao;
import robocode.rescue.features.RedeNeuralFunctions;
import robocode.rescue.features.RoboAtaque;
import robocode.rescue.interfaces.RMIRobotInterface;

public class TimeDTeamEnv extends RoborescueEnv {

    private final int numRobos = 5;
    private RobotInfo[] robos;
    private RobotInfo[] robosInimigos;
    private int wasCalledRNA = 0;
    
    /**
     * Atributos Ataque!
     * 
     * Obs: atributo distanciaAnterior e distanciaAtual estão na classe RobotInfo
     */
    private RoboAtaque[] roboAtaque;
    private int auxRoboDois;
    private int auxRoboTres;
    
    private double[] inputsAtaqueRNA; // 4 inputs para a RNA de ataque.
    private double[] angulosRobos; //utilizado para conseguir a informação dos ângulos dos robôs.
    
    private RedeNeuralFunctions rna;
    
    /**
     * Atributos Defesa!
     */

    final double PI = Math.PI;          //somente um constante.
    Movimentacao mv = new Movimentacao();

    //Para inicializacoes necessarias
    @Override
    public void setup() {
        robos = new RobotInfo[numRobos];
        roboAtaque = new RoboAtaque[numRobos];
        
        inputsAtaqueRNA = new double[4]; //neste caso ele irá passar os inputs para a rede neural roboinimigo1 = inputsAtaqueRNA[0].
        angulosRobos = new double[numRobos];
        
        for (int i = 0; i < roboAtaque.length; i++) {
            roboAtaque[i] = new RoboAtaque();
        }
    }

    @Override
    public boolean executeAction(String ag, Structure action) {

        try {
            mainLoop();
            Thread.sleep(20);
        } catch (RemoteException ex) {
            ex.printStackTrace();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }

        return true;

    }

    public void mainLoop() throws RemoteException {

        robos = getServerRef().getMyTeamInfo(myTeam);
        robosInimigos = getServerRef().getEnemyTeamInfo(myTeam);
        
        rna = new RedeNeuralFunctions();
        
        RobotInfo refem = robos[0];
        double xRefem = refem.getX();
        double yRefem = refem.getY();
        
        //referência do nosso time!!!
        RMIRobotInterface[] teamRef = getTeamRef();
        
        /**
         * LÓGICA GERAL!!!
         */
        
        //percorre todos os robôs para dar a eles ações!
        for (int robo = 1; robo < numRobos; robo++){
            
            /**
              * LÓGICA ATAQUE! robôs 2 e 3 começam atacando!
              * 
              * Obs: Quando o robô inimigo não estiver dentro do range de distância (500px), porém existir um outro(s) dentro do
              * range estipulado será enviado o parâmetro -1 para a RNA!
              */
            
            //SE O REFÉM NÃO ESTIVER SEGUINDO!
            if(teamRef[0].isFollowing() == 0){
                
                if (robo == 1 || robo == 3)
                {
                    
                    //variável auxiliar para verificar se existe algum robô com menos de 500px de distância!!!
                    auxRoboDois = 0;

                    //buscar distância do robô até todos os outros 5 robôs inimigos.
                    roboAtaque[robo].setDistanciaAtual(mv.distanciaRobo(robos[robo], robosInimigos));

                    //se todas as distâncias atuais estiverem maior que 400px então o robô segue seu destino "buscar refém".
                    for (int i = 1; i < roboAtaque[robo].getDistanciaAtual().length; i++) {

                        if(roboAtaque[robo].getDistanciaAtual()[i] < 250 && robos[robo].getX() < robosInimigos[i].getX()){
                            auxRoboDois++;
                        }

                    }

                    //se a distância para todos os robôs for maior que 500px ele irá seguir seu caminho normal em busca do refém.
                    if(auxRoboDois == 0){
                        
                        System.out.println("indo em direção ao refém.");
                        mv.goTo(robos[0].getX(), robos[0].getY(), robos[robo], teamRef[robo]);
                        wasCalledRNA = 0;
                    }
                    else{ //lógica para chamar a RNA ataque.

                        //auxRoboDois = 0;

                        //ângulos para todos os robôs.
                        angulosRobos = mv.angulosRobo(robos[robo], robosInimigos);

                        for (int i = 1; i < roboAtaque[robo].getDistanciaAtual().length; i++) {

                            //LÓGICA importante - adicionando informação no array de Input para a RNA.
                            if(roboAtaque[robo].getDistanciaAtual()[i] < 250 && robos[robo].getX() < robosInimigos[i].getX()){

                                //lógica OK - irá adicionar o ângulo do robô no array de input para a RNA de ataque.
                                //inputsAtaqueRNA[i-1] = angulosRobos[i];
                                inputsAtaqueRNA[i-1] = mv.anguloRNA(angulosRobos[i]);

                                //auxRoboDois++;
                            }else{

                                //lógica NOK - irá adicionar o ângulo default (360) no array de input para a RNA de ataque.
                                //inputsAtaqueRNA[i-1] = 360;
                                inputsAtaqueRNA[i-1] = 0;
                            }

                        }

                        //verificação - se auxRoboDois for "0" então não precisará chamar a RNA e o caminho do robô deverá seguir para o refém;
                        //caso contrário irá chamar a RNA de ataque!
                        //if(auxRoboDois > 0){

                            //chama a RNA com os inputs!!!
                            

                                //chama a rna ex - rnaataque(inputsAtaqueRNA[0], inputsAtaqueRNA[1], inputsAtaqueRNA[2], inputsAtaqueRNA[3]);                            
                                System.out.println("chamando rede neural, desviando!");                            
                                //System.out.println("Parâmetro RNA ---");
                                //System.out.println("robô inimigo 1: "+inputsAtaqueRNA[0]);
                                //System.out.println("robô inimigo 2: "+inputsAtaqueRNA[1]);
                                //System.out.println("robô inimigo 3: "+inputsAtaqueRNA[2]);
                                //System.out.println("robô inimigo 4: "+inputsAtaqueRNA[3]);
                                //System.out.println("");
                                mv.goToAngulo(rna.getNeuralAngleDesvio(inputsAtaqueRNA[0]/100, inputsAtaqueRNA[1]/100, inputsAtaqueRNA[2]/100, inputsAtaqueRNA[3]/100), robos[robo], teamRef[robo]); //robo usa o retorno da rna para conseguir desviar dos inimigos.
                            
                            
                        //}
                        //else{

                            //vai pelo caminho normal!!!! (em busca do refém!)
                            //mv.goTo(robos[0].getX(), robos[0].getY(), robos[2], teamRef[2]);
                            //System.out.println("conseguiu desviar, indo em busca do refém!");
                        //}
                    } //fim lógica RNA ataque!
                    
                    //chama o método de "verificação robô bloqueado"...
                    roboAtaque[robo].roboBloqueado(robos[robo], teamRef[robo]);

                }
                
            }
            //SE O REFÉM ESTIVER SEGUINDO!!!!! (basicamente a lógica inversa!)
            else{
                
                if(robo == 1 || robo == 3)
                {
                    //variável auxiliar para verificar se existe algum robô com menos de 500px de distância!!!
                    auxRoboDois = 0;

                    //buscar distância do robô até todos os outros 5 robôs inimigos.
                    roboAtaque[robo].setDistanciaAtual(mv.distanciaRobo(robos[robo], robosInimigos));

                    //se todas as distâncias atuais estiverem maior que 400px então o robô segue seu destino "buscar refém".
                    for (int i = 1; i < roboAtaque[robo].getDistanciaAtual().length; i++) {

                        if(roboAtaque[robo].getDistanciaAtual()[i] < 250 && robos[robo].getX() > robosInimigos[i].getX()){
                            auxRoboDois++;
                        }

                    }

                    //se a distância para todos os robôs for maior que 500px ele irá seguir seu caminho normal em busca do refém.
                    if(auxRoboDois == 0){
                        //mv.goTo(robos[0].getX(), robos[0].getY(), robos[2], teamRef[2]);
                        mv.goTo(50, 500, robos[robo], teamRef[robo]);
                        System.out.println("voltando com o nosso amigo.");
                    }
                    else{ //lógica para chamar a RNA ataque.

                        //auxRoboDois = 0;

                        //ângulos para todos os robôs.
                        angulosRobos = mv.angulosRobo(robos[robo], robosInimigos);

                        for (int i = 1; i < roboAtaque[robo].getDistanciaAtual().length; i++) {

                            //LÓGICA importante - adicionando informação no array de Input para a RNA.
                            if(roboAtaque[robo].getDistanciaAtual()[i] < 250 && robos[robo].getX() > robosInimigos[i].getX()){

                                //lógica OK - irá adicionar o ângulo do robô no array de input para a RNA de ataque.
                                //inputsAtaqueRNA[i-1] = angulosRobos[i];
                                inputsAtaqueRNA[i-1] = mv.anguloRNA(angulosRobos[i]);

                                //auxRoboDois++;
                            }else{

                                //lógica NOK - irá adicionar o ângulo default (360) no array de input para a RNA de ataque.
                                //inputsAtaqueRNA[i-1] = 360;
                                inputsAtaqueRNA[i-1] = 0;
                            }

                        }

                        //verificação - se auxRoboDois for "0" então não precisará chamar a RNA e o caminho do robô deverá seguir para o refém;
                        //caso contrário irá chamar a RNA de ataque!

                            //chama a RNA com os inputs!!!
                            
                            //chama a rna ex - rnaataque(inputsAtaqueRNA[0], inputsAtaqueRNA[1], inputsAtaqueRNA[2], inputsAtaqueRNA[3]);
                            mv.goToAngulo(210, robos[robo], teamRef[robo]); //robo usa o retorno da rna para conseguir desviar dos inimigos.
                            System.out.println("chamando rede neural, desviando!");
                            
                                System.out.println("Parâmetro RNA ---");
                                System.out.println("robô inimigo 1: "+inputsAtaqueRNA[0]);
                                System.out.println("robô inimigo 2: "+inputsAtaqueRNA[1]);
                                System.out.println("robô inimigo 3: "+inputsAtaqueRNA[2]);
                                System.out.println("robô inimigo 4: "+inputsAtaqueRNA[3]);
                                System.out.println("");
                      
                    } //fim lógica RNA ataque!
                    
                    //chama o método de "verificação robô bloqueado"...
                    roboAtaque[robo].roboBloqueado(robos[robo], teamRef[robo]);
                }
                
            }
              
            /**
              * LÓGICA DEFESA! robôs 1 e 4 começam defendendo!
              */
            
            if (robo == 1)
            {
                
            }
            
            if(robo == 4)
            {
                
            }
            
        } //fim - laço percorrer todos os robôs.
    }

    @Override
    public void end() {
        try {
            super.getEnvironmentInfraTier().getRuntimeServices().stopMAS();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.exit(1);
        }
    }

    public static void main(String[] args) {
        TimeDTeamEnv team = new TimeDTeamEnv();
        team.init(new String[]{"TimeD", "localhost"});
        team.setup();
        while (true) {
            try {
                team.mainLoop();
                Thread.sleep(20);
            } catch (RemoteException ex) {
                ex.printStackTrace();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
    
}